package com.lagou.filter;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * @ClassName: IpCountFilter
 * @Auther: Jerry
 * @Date: 2020/10/28 15:08
 * @Desctiption: TODO
 * @Version: 1.0
 */
@Component
public class IpCountFilter implements GlobalFilter, Ordered {

    /**
     * ip请求统计
     */
    private ConcurrentMap<String, IpCount> ipCountMap = new ConcurrentHashMap<>();

    /**
     * 将毫秒数转为分钟数
     */
    private static final Integer MINUTE_UNIT = 1000 * 60;

    private PathMatcher matcher = new AntPathMatcher();

    /**
     * 需要拦截的路径
     */
    private static final String FILTER_PATH = "/api/user/register/**";

    @Value("${maxRequest}")
    private Integer maxRequest;

    @Value("${limitTimeMinute}")
    private Integer limitTimeMinute;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //限制单个客户端IP在最近X分钟内请求注册接口不能超过Y次
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        // 获取请求路径
        String path = request.getURI().getPath();
        // 判断是否是注册接口的路径
        if (matcher.match(FILTER_PATH, path)) {
            // 获取请求的ip
            String ip = request.getRemoteAddress().getHostString();
            System.out.println("ip" + ip);
            IpCount ipCount = ipCountMap.get(ip);
            if (ipCount == null) {
                // 记录此ip第一次请求的时间戳
                ipCount = new IpCount();
                ipCount.setFirstTime(System.currentTimeMillis());
                // 第一次请求
                ipCount.setTimes(1);
                ipCountMap.put(ip, ipCount);
                return chain.filter(exchange);
            } else {
                if (((System.currentTimeMillis() - ipCount.getFirstTime())) / MINUTE_UNIT <= limitTimeMinute) {
                    if (ipCount.getTimes() <= maxRequest) {
                        // 每请求一次，请求次数+1
                        ipCount.setTimes(ipCount.getTimes() + 1);
                        ipCountMap.put(ip, ipCount);
                        return chain.filter(exchange);
                    } else { // 客户端IP在最近limitTimeMinute分钟内请求注册接口超过maxRequest次
                        // 您频繁进行注册，请求被拒绝
                        response.setStatusCode(HttpStatus.SEE_OTHER);
                        return response.setComplete();
                    }
                } else {
                    // 已超过限制时间，重置请求次数及请求时间
                    ipCount.setFirstTime(System.currentTimeMillis());
                    ipCount.setTimes(1);
                    ipCountMap.put(ip, ipCount);
                    chain.filter(exchange);
                }
            }
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -1;
    }

    class IpCount{
        private long firstTime;
        private int times;
        public long getFirstTime() {
            return firstTime;
        }
        public void setFirstTime(long firstTime) {
            this.firstTime = firstTime;
        }
        public int getTimes() {
            return times;
        }
        public void setTimes(int times) {
            this.times = times;
        }
    }
}
